package com.samp.solr.solrlstm;


import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.HttpClient;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrClient;
import org.apache.solr.client.solrj.impl.HttpClientUtil;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 各种常量信息
 */
public class SolrlstmUtils {
    public static String BASE_PATH = "D:\\solrlstm\\";

    public static final String SOLR_FIELD_ID = "id";
    public static final String SOLR_FIELD_CONTENT = "content";
    public static final String SOLR_FIELD_INTENTION = "intention";
    public static final String SOLR_FIELD_CONTENT_FULL_MATCH = "contentFullMatch";
    public static final String BASE_SOLR_URL = "http://localhost:8080/solr/";
    public static final Integer TOP_N = 10;

    public static final Float MIN_SCORE = 4.0f; //最小分值
    public static final Float MIN_RATE = 1.1f; //最小比值

    private static Map<String,Float> weightMap = new HashMap<>();

    /**
     * 去除意图中的第四个槽位。
     * @param intention
     * @return
     */
    public static String removeLastSlot(String intention){
        String[] intentions = intention.split("#");
        if( intentions.length < 4 ){
            return intention;
        }
        String newIntention = intentions[0]+"#"+intentions[1]+"#"+intentions[2];
        return newIntention;
    }

    public static SolrClient getUpdateSolrClient(String solrUrl) throws Exception{
        ModifiableSolrParams params = new ModifiableSolrParams();
        params.set(HttpClientUtil.PROP_MAX_CONNECTIONS, 128);
        params.set(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST, 32);
        params.set(HttpClientUtil.PROP_FOLLOW_REDIRECTS, false);
        params.set(HttpClientUtil.PROP_ALLOW_COMPRESSION, true);
        params.set(HttpClientUtil.PROP_USE_RETRY, true);
        HttpClient httpClient = HttpClientUtil.createClient(params);
        ConcurrentUpdateSolrClient updateSolrClient = new ConcurrentUpdateSolrClient.Builder(solrUrl)
                .withHttpClient(httpClient).withQueueSize(100).withThreadCount(10).build();
        updateSolrClient.setConnectionTimeout(1000);
//        updateSolrClient.setSoTimeout(1000);
        updateSolrClient.setPollQueueTime(500);
        return updateSolrClient;
    }

    public static List<WordIntention> getTopNIntentions(SolrClient solrClient, String word, Integer topN) throws Exception{
        try{
            SolrQuery query = new SolrQuery();
            query.set(CommonParams.QT, "/select");
            query.set(CommonParams.START, "0");
            query.set(CommonParams.ROWS, topN);
            String queryParam = generateQueryParam(word);
            query.set(CommonParams.Q, queryParam);
            query.set(CommonParams.FL, SOLR_FIELD_CONTENT+","+SOLR_FIELD_INTENTION+",score");
            List<WordIntention> resultList = new ArrayList<>();
            QueryResponse response = solrClient.query(query);
            SolrDocumentList documentList = response.getResults();
            for( SolrDocument doc : documentList ) {
                WordIntention wi = new WordIntention();
                String docContent = (String) doc.getFieldValue(SOLR_FIELD_CONTENT);
                String docIntention = (String) doc.getFieldValue(SOLR_FIELD_INTENTION);
                Float docScore = (Float) doc.getFieldValue("score");
                wi.setWord(docContent);
                wi.setIntention(docIntention);
                wi.setScore(docScore);
                resultList.add(wi);
            }
            return resultList;
        }catch (Exception e){
            throw new Exception("error word:"+word,e);
        }
    }

    public static String generateQueryParam(String word){
        return SOLR_FIELD_CONTENT+":"+addWeightToWord(word)+" OR "+ SOLR_FIELD_CONTENT_FULL_MATCH+":"+"\""+word+"\"^8";
    }

    private static String addWeightToWord(String word){
        if( StringUtils.isBlank(word) ){
            return word;
        }
        String[] wordSplits = word.split(" ");
        String[] weightWord = new String[wordSplits.length];
        for(int i = 0 ;i < wordSplits.length ; i++ ){
            if( weightMap.containsKey(wordSplits[i]) ){
                weightWord[i]=wordSplits[i]+"^"+String.valueOf(weightMap.get(wordSplits[i]));
            }else {
                weightWord[i]=wordSplits[i];
            }
        }
        return StringUtils.join(weightWord, " ");
    }

    public static void initialWeightMap(String weightPath){
        System.out.println("start initial weight map...");
        String rawPath = weightPath;
        Path filePath = Paths.get(rawPath);
        BufferedReader bufferReader = null;
        try {
            bufferReader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8);
            String line;
            while ((line = bufferReader.readLine()) != null) {
                if( StringUtils.isNotBlank(line) ){
                    //如果注释掉，直接continue.
                    String data = line.trim();
                    if( data.startsWith("#") ){
                        continue;
                    }
                    String[] splits = data.split(",");
                    if( splits.length >= 2 ){
                        try {
                            for( int i = 1 ; i< splits.length ; i++ ){
                                weightMap.put(splits[i].trim(), Float.valueOf(splits[0]));
                            }
                        }catch (Exception e1){
                            e1.printStackTrace();
                        }
                    }else {
                        System.out.println("error line:"+line);
                    }
                }
            }
            System.out.println("加载关键字权重个数："+weightMap.size());
        }catch (IOException e) {
            e.printStackTrace();
        }finally{
            if( bufferReader != null ) {
                try {
                    bufferReader.close();
                }catch (Exception e1){
                    e1.printStackTrace();
                }
            }
        }
    }

    public static String appendLastSlot(String intention, String words){
        //暂时不添加四个槽位
        return intention;
//        if( lastSlotMap.get(intention.trim()) == null ) {
////            System.out.println("last slot not found in map:"+intention);
//            return intention;
//        }
//        List<String> slotList = lastSlotMap.get(intention.trim());
//        //如果槽位只有一个值，直接补上
//        String lastSlotName = "default";
//        if( slotList.size() == 1 ){
//            lastSlotName = slotList.get(0);
//        }else if(slotList.size() == 2 && slotList.contains("default")){
//            for(String s:slotList){
//                if( !"default".equals(s) ){
//                    lastSlotName = s;
//                    break;
//                }
//            }
//        }else {
//            for(String lastSlot:slotList){
//                if( "default".equals(lastSlot) ){
//                    continue;
//                }
//                if( isWordsMatchLastSlot(lastSlot, words) ){
//                    lastSlotName = lastSlot;
//                    break;
//                }
//            }
//        }
//        return intention+"#target.params2="+lastSlotName;
    }

    public static boolean isEqualIntention(String oriIntention, String solrIntention){
        if( oriIntention.equals(solrIntention) ){
            return true;
        }
        // action.name=转人工#target.name=default#target.params1=default和
        // action.name=default#target.name=转人工#target.params1=default 认为是相等的。
        String toManual1 = "action.name=转人工#target.name=default#target.params1=default";
        String toManual2 = "action.name=default#target.name=转人工#target.params1=default";
        if( (oriIntention.equals(toManual1) || oriIntention.equals(toManual2)) &&
                ( solrIntention.equals(toManual1) || solrIntention.equals(toManual2)) ){
            return true;
        }
        //如果第四个槽位，只有default和其它值，则前三个槽位相等也认为相等.
        String[] oriSplits = oriIntention.split("#");
        String[] solrSplits = solrIntention.split("#");
        if( oriSplits.length == 4 && solrSplits.length == 4 ){
            if( oriSplits[0].equals(solrSplits[0]) && oriSplits[1].equals(solrSplits[1])
                    && oriSplits[2].equals(solrSplits[2]) ){
                return true;
//                String key = oriSplits[0]+"#"+oriSplits[1]+"#"+oriSplits[2];
//                List<String> slotList = lastSlotMap.get(key.trim());
//                if( slotList == null ){
//                    System.out.println("error key:"+key.trim());
//                }else if( slotList.size() == 2 && slotList.contains("default") ) {
//                    return true;
//                }
            }
        }
        return false;
    }

    /**
     * 将意图转换为一条新的语料.
     * @param rawIntention
     * @return
     */
    public static String intentionToWord(String rawIntention){
        List<String> list = new ArrayList<>();
        String[] intentionSplits = rawIntention.trim().split("#");
        for( int i = 0 ;i < intentionSplits.length ; i++ ){
            String intention = intentionSplits[i];
            String[] details = intention.split("=");
            if( details.length < 2 ){
                return null;
            }
            if(  !"default".equals(details[1]) && !"execute".equals(details[1])
                    && !"chat".equals(details[1]) && !"集外".equals(details[1]) ){
                list.add(TokenizeUtils.tokenize(details[1]));
            }
        }
        return StringUtils.join(list.iterator(), " ");
    }

    /**
     * 提取意图文字信息，用于训练
     * @param intention
     */
    public static String extractIntentionWord(String intention){
        String[] splits = intention.split("#");
        List<String> list = new ArrayList<>();
        for(String s :splits){
            String[] details = s.split("=");
            if( details.length != 2 ){
                return null;
            }
            if(  !"default".equals(details[1]) && !"execute".equals(details[1]) ){
                list.add(details[1]);
            }
        }
        return StringUtils.join(list," ");
    }


    /**
     * 返回第二个Match.查找规则：
     * 0：如果list大小为1，直接返回null;
     * 1：与第一个的意图不相同
     * 2：如果所有意图都相同，返回null
     * @param list
     * @return
     */
    public static WordIntention getSecondMatch(List<WordIntention> list){
        if( list.size() == 1 ){
            return null;
        }
        for( int i = 1 ; i < list.size(); i++){
            if( !list.get(i).getIntention().equalsIgnoreCase(list.get(0).getIntention()) ){
                return list.get(i);
            }
        }
        return null;
    }

    /**
     * 判断solr返回结果是否满足。
     * 1:如果second为空，判断first的score是否满足param1
     * 2:如果second不为空，则两个都要判断。
     * @param first
     * @param second
     * @return
     */
    public static boolean isSatisfyThreshold(WordIntention first, WordIntention second) throws Exception{
        if( first == null ){
            throw new Exception("first WordIntention can not be null");
        }
        if( first.getScore() >= MIN_SCORE ){
            if( second == null || first.getScore().floatValue()/second.getScore().floatValue() >= MIN_RATE) {
                return true;
            }
        }
        return false;
    }

    /**
     * 如果不满足阈值，取Top5的意图进模型匹配
     * @param list
     * @return
     */
    public static String getNoSatisfyIntentionSet(List<WordIntention> list){
        List<String> resultList = new ArrayList<>();
        for( WordIntention wi: list ){
//            if( !resultList.contains(extractIntentionWord(wi.getIntention())) ) {
//                resultList.add(extractIntentionWord(wi.getIntention()));
//            }
            if( !resultList.contains(wi.getWord()) ) {
                resultList.add(wi.getWord()+"|"+extractIntentionWord(wi.getIntention()));
            }
        }
        return StringUtils.join(resultList,";");
    }

    public static void main(String[] args) {
        String callmethod = "generateQueryParam";
        String callMethod = "validateTestFile";
        String collectionDirName = "lifeareanavi";
        String collectionFullPath = SolrlstmUtils.BASE_PATH+collectionDirName+"\\";
        try{
            if( "generateQueryParam".equals(callmethod) ){
                String weightPath = collectionFullPath+"tokenize_weight_xx.txt";
                initialWeightMap(weightPath);
                String text = "想问 挂 什么 金管家 里面";
                System.out.println(generateQueryParam(text));
            }
        }catch (Exception e){

        }
    }
}
